package net.zoneland.zrdp.biz.service.impl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import javax.annotation.Resource;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Preconditions;

import cn.hutool.core.date.DatePattern;
import net.zoneland.zrdp.biz.domain.AuditTarget;
import net.zoneland.zrdp.biz.enums.CompanyEnum;
import net.zoneland.zrdp.biz.mapper.AuditTargetMapper;
import net.zoneland.zrdp.biz.service.IAuditTargetService;


/**
 * 审计对象数据Service业务层处理
 * 创建日期: 2024-03-14
 * @author helu
 */
@Service
public class AuditTargetServiceImpl implements IAuditTargetService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AuditTargetServiceImpl.class);

    /** 对象库excel表格忽略行数. */
    private static final int EXCEL_TITLE_ROWS = 4;
    /** 导入错误提示. */
    private static final String ERROR_MSG = "<br/>第%d行对象：%s导入失败：";

    /** 一年的月份数量. */
    private static final int MONTH_NUMBER = 12;
    /** 当前依旧任职的任职结束时间描述. */
    private static final String OFFICE_TIME_DESCRIPTION = "至今";
    /** 默认每月的第一天. */
    private static final String FIRST_DAY = "01";
    /** 创新研究院名称. */
    private static final String INNOVATION_RESEARCH_INSTITUTE = "创新研究院";
    /** 集成公司名称. */
    private static final String INTEGRATION_COMPANY = "集成公司";
    /** 单位标题. */
    private static final String COMPANY_TITLE = "所属二级单位名称";
    /** 经理人员姓名标题. */
    private static final String MANAGE_NAME_TITLE = "经理人姓名";
    /** 任职开始时间标题. */
    private static final String COMMENCEMENT_OFFICE_TITLE = "任职开始时间";
    /** 任职结束时间标题. */
    private static final String END_OF_SERVICE_TITLE = "任职结束时间";
    /** 为空错误提示. */
    private static final String NOT_NULL_MSG = "不能为空";
    /** 单位名称错误提示. */
    private static final String COMPANY_ERROR_MSG = "所属二级单位必须要是11个地市名称或者创新研究院和集成公司";
    /** excel模版错误提示. */
    private static final String EXCEL_ERROR = "导入模板错误！";

    @Resource
    private AuditTargetMapper auditTargetMapper;

    /**
     * 查询审计对象数据.
     * @param id 审计对象数据主键
     * @return 审计对象数据
     */
    @Override
    public AuditTarget selectAuditTargetById(final String id) {
        return auditTargetMapper.selectAuditTargetById(id);
    }

    /**
     * 查询审计对象数据列表.
     * @param auditTarget 审计对象数据
     * @return 审计对象数据
     */
    @Override
    public List<AuditTarget> selectAuditTargetList(final AuditTarget auditTarget) {
        return auditTargetMapper.selectAuditTargetList(auditTarget);
    }

    /**
     * 批量导入审计对象数据.
     * @param auditTargetList 审计对象数据
     * @return 结果
     */
    @Override
    public int insertBatchAuditTarget(final List<AuditTarget> auditTargetList) {
        return auditTargetMapper.insertBatchAuditTarget(auditTargetList);
    }

    /**
     * 导入审计对象数据.
     * @author helu
     * @Date 17:52 2024/3/12
     * @param targetList 审计对象数据
     * @return 导入结果
     */
    @Override
    @Transactional
    public String importAuditTargets(final List<AuditTarget> targetList) {
        //校验模板
        Preconditions.checkArgument(CollectionUtils.isNotEmpty(targetList)
            && !allCompaniesBlank(targetList), EXCEL_ERROR);

        //删除原有的对象数据
        auditTargetMapper.deleteAllAuditTarget();

        //遍历所有对象信息并保存，同时记录导入失败的信息
        final LocalDateTime nowTime = LocalDateTime.now();
        final StringBuilder failureMsg = new StringBuilder(); //记录错误信息
        final ListIterator<AuditTarget> targetIterator = targetList.listIterator();
        final List<AuditTarget> auditList = new ArrayList<>();
        while(targetIterator.hasNext()) {
            final AuditTarget auditTarget = targetIterator.next();
            try {
                //校验导入的数据
                checkAuditTarget(auditTarget);

                auditTarget.setCreateTime(nowTime);
                auditTarget.setEmploymentPeriod(getEmploymentTime(auditTarget.getCommencementOfOffice(),
                    auditTarget.getEndOfService()));
                auditList.add(auditTarget);
            } catch (final Exception e) { //不确定导入的数据在校验和转换的时候可能出现多少异常
                //记录错误信息
                final String msg = String.format(ERROR_MSG,
                    targetIterator.nextIndex() + EXCEL_TITLE_ROWS, auditTarget.getName());
                failureMsg.append(msg);
                LOGGER.error("导入审计对象失败，错误数据:{}", msg, e);
            }
        }
        final String errorMsg = failureMsg.toString();

        //如有错误信息就抛出异常
        Preconditions.checkArgument(StringUtils.isBlank(errorMsg), errorMsg);

        //批量导入审计对象
        insertBatchAuditTarget(auditList);
        return errorMsg;
    }

    /**
     * 判断公司名称是否全部为空.
     * @author helu
     * @Date 14:35 2024/5/10
     * @param targetList 审计对象
     * @return boolean 结果
     */
    private boolean allCompaniesBlank(final List<AuditTarget> targetList) {
        return targetList.stream()
            .map(AuditTarget::getCompany)
            .allMatch(StringUtils::isBlank);
    }

    /**
     * 校验导入的被审计对象数据.
     * @author helu
     * @Date 17:17 2024/4/9
     * @param auditTarget 导入对象
     */
    private void checkAuditTarget(final AuditTarget auditTarget) {
        final String company = auditTarget.getCompany();
        Preconditions.checkArgument(StringUtils.isNotBlank(company), COMPANY_TITLE + NOT_NULL_MSG);
        Preconditions.checkArgument(StringUtils.isNotBlank(auditTarget.getName()), COMMENCEMENT_OFFICE_TITLE + NOT_NULL_MSG);
        Preconditions.checkArgument(StringUtils.isNotBlank(auditTarget.getCommencementOfOffice()), COMMENCEMENT_OFFICE_TITLE + NOT_NULL_MSG);
        Preconditions.checkArgument(StringUtils.isNotBlank(auditTarget.getEndOfService()), END_OF_SERVICE_TITLE + NOT_NULL_MSG);
        Preconditions.checkArgument(CompanyEnum.anyEquals(company)
                || StringUtils.equalsAny(company, INNOVATION_RESEARCH_INSTITUTE, INTEGRATION_COMPANY), COMPANY_ERROR_MSG);
    }

    /**
     * 获取任职时间/月.
     * @author helu
     * @Date 9:42 2024/3/26
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 任职时间/月
     */
    private String getEmploymentTime(final String startTime, final String endTime) {
        final LocalDate endDate = StringUtils.equals(endTime, OFFICE_TIME_DESCRIPTION)
            ? LocalDate.now() : LocalDate.parse(endTime + FIRST_DAY, DatePattern.PURE_DATE_FORMATTER);
        final Period period = Period.between(LocalDate.parse(startTime + FIRST_DAY,
            DatePattern.PURE_DATE_FORMATTER), endDate);
        return period.getYears() * MONTH_NUMBER + period.getMonths() + StringUtils.EMPTY;
    }
}
